package com.github.icloudpay.pay.core.service.pay.wechat.service;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.lang.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.github.icloudpay.pay.core.biz.PayChannelConfigBiz;
import com.github.icloudpay.pay.core.entity.PayChannelConfig;
import com.github.icloudpay.pay.core.inter.PayObjectService;
import com.github.icloudpay.pay.core.service.pay.wechat.domain.RequestElement;
import com.github.icloudpay.pay.core.service.pay.wechat.util.WechatPayConfig;
import com.github.wxiaoqi.security.common.admin.pay.request.OnlinePaymentRequest;
import com.github.wxiaoqi.security.common.msg.ResponseCode;
import com.github.wxiaoqi.security.common.util.Utils;


/**
 * 微信APP支付
 * @author hexufeng
 *
 */
@Service("wechatAppPaymentService")
public class WechatAppPaymentService implements PayObjectService<OnlinePaymentRequest>{

	private static final Logger logger = (Logger) LoggerFactory.getLogger(WechatAppPaymentService.class);
	
	@Autowired
	private PayChannelConfigBiz payChannelConfigBiz;
	@Autowired
	private WechatSignatureService wechatSignatureService;
	@Autowired
	private WechatPayConfig wechatPayConfig;


	public Map<String, Object> pay(OnlinePaymentRequest request){
		
		logger.info("****************调用微信APP支付接口开始*******************");

		Map<String, Object> responseMap = new HashMap<String, Object>();

		PayChannelConfig payChannelConfig = new PayChannelConfig();
		payChannelConfig.setMerId(request.getMerId());
		payChannelConfig.setPlatformId(request.getPlatformId());
		payChannelConfig.setPayChannelNo(request.getPayChannelNo());
		payChannelConfig.setPayCompanyNo(request.getPayCompanyNo());
		PayChannelConfig channelConfig = payChannelConfigBiz.getPayChannelConfig(payChannelConfig);
		if(null == channelConfig){
			responseMap.put("sucess", false);
			responseMap.put("code", ResponseCode.PAYCHANNEL_CONFIGURATION_NOTEXIST.getCode());
			responseMap.put("msg", ResponseCode.PAYCHANNEL_CONFIGURATION_NOTEXIST.getMessage());
			return responseMap;
		}
		String notifyUrl = wechatPayConfig.getBackCallbackUrl() + "/callBack/wechatPay";

		String nonce_str=ObjectUtils.toString((new Random().nextInt() * (99999 - 10000 + 1)) + 10000);

		//根据获取的参数拼装XML信息
		RequestElement reqElement = new RequestElement();
		reqElement.setAppid(channelConfig.getOutMerAccount());
		reqElement.setBody(request.getProductName());
		reqElement.setMch_id(channelConfig.getOutMerNo());
		reqElement.setNonce_str(nonce_str);
		reqElement.setNotify_url(notifyUrl);
		reqElement.setOut_trade_no(request.getSerialNo());
		reqElement.setSpbill_create_ip(request.getExterInvokeIp());
		reqElement.setTotal_fee(Utils.changeToDivide(request.getOrderAmt().toString()));
		reqElement.setTrade_type("APP");

		//获取签名信息
		try {
			reqElement.setSign(wechatSignatureService.sign(reqElement, channelConfig));
		} catch (Exception e1) {
			e1.printStackTrace();
		}

		String xmlStr = null;
		try {
			xmlStr = reqData2Xml(reqElement);
		} catch (JAXBException e) {
			logger.error("解析微信返回数据失败",e);
			responseMap.put("sucess", false);
			responseMap.put("code", ResponseCode.WECHAT_RESOLVE_FAIL.getCode());
			responseMap.put("msg", ResponseCode.WECHAT_RESOLVE_FAIL.getMessage());
			return responseMap;
		} 

		//        调用微信统一下单接口
		String payUrl = wechatPayConfig.getWechatGatewayUrl(); 
		HttpClient client=new HttpClient();
		PostMethod post=new PostMethod(payUrl);
		Map<String,Object> resultMap=new HashMap<String, Object>();
		try {  
			RequestEntity entity = new StringRequestEntity(xmlStr, "text/xml",  
					"UTF-8");  
			logger.info("xmlStr:{}",xmlStr);
			post.setRequestEntity(entity);  
			client.executeMethod(post);   
			int code = post.getStatusCode();  
			if (code == HttpStatus.SC_OK){ 
				String info = new String(post.getResponseBody(),"UTF-8");  
				logger.info("微信返回结果：", info);
				resultMap =receiveResult(info,channelConfig);
				logger.info("发送成功，返回的结果：", resultMap);
				responseMap.put("payInfo", resultMap);
				responseMap.put("sucess", true);
		        responseMap.put("code", ResponseCode.OK.getCode());
		        responseMap.put("msg", ResponseCode.OK.getMessage());
			}else{
				logger.error("发送数据失败");
				responseMap.put("sucess", false);
				responseMap.put("code", ResponseCode.SEND_DATA_FAIL.getCode());
				responseMap.put("msg", ResponseCode.SEND_DATA_FAIL.getMessage());
			}

		} catch (Exception ex) {  
			logger.error("返回失败",ex);
			ex.printStackTrace();  
		} finally {  
			post.releaseConnection();  
		}  
		return responseMap;

	}

	/**
	 * 将请球参数转为Xml格式
	 * @throws JAXBException 
	 * @throws ParserConfigurationException 
	 */
	private String reqData2Xml(RequestElement reqElement) throws JAXBException{
		JAXBContext context = JAXBContext.newInstance(RequestElement.class);

		Marshaller marshaller = context.createMarshaller();
		marshaller.setProperty(Marshaller.JAXB_ENCODING,"UTF-8");//编码格式
		marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);//是否格式化生成的xml串
		marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);//是否省略xml头信息（<?xml version="1.0" encoding="gb2312" standalone="yes"?>）

		ByteArrayOutputStream outputstream = new ByteArrayOutputStream();

		StreamResult result = new StreamResult(outputstream);

		marshaller.marshal(reqElement, result);

		byte[] body = outputstream.toByteArray();

		return new String(body,Charset.forName("UTF-8"));
	}


	/**
	 * 解析获取的返回结果
	 * @param info
	 * @return
	 * @throws ParserConfigurationException 
	 * @throws IOException 
	 * @throws SAXException 
	 */
	private  Map<String,Object> receiveResult(String info,PayChannelConfig channelConfig) throws ParserConfigurationException, SAXException, IOException{


		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = factory.newDocumentBuilder();
		InputStream is =  getStringStream(info);
		Document document = builder.parse(is);


		//获取到document里面的全部结点
		NodeList allNodes = document.getFirstChild().getChildNodes();
		Node node;
		Map<String, Object> paramMap = new HashMap<String, Object>();
		int i=0;
		while (i < allNodes.getLength()) {
			node = allNodes.item(i);
			if(node instanceof Element){
				paramMap.put(node.getNodeName(),node.getTextContent());
			}
			i++;
		}
		//        Date dt=new Date();
		String timeStamp=String.valueOf(System.currentTimeMillis()/1000);
		Map<String, Object> resultMap = new HashMap<String, Object>();
		Random random = new Random();


		resultMap.put("appid", paramMap.get("appid"));
		resultMap.put("timestamp", timeStamp);
		resultMap.put("partnerid", paramMap.get("mch_id"));
		resultMap.put("prepayid", paramMap.get("prepay_id"));
		resultMap.put("package", "Sign=WXPay");
		resultMap.put("noncestr", ObjectUtils.toString((random.nextInt() * (99999 - 10000 + 1)) + 10000));
		resultMap.put("sign",wechatSignatureService.toSign(resultMap, channelConfig));
		resultMap.put("return_code", paramMap.get("return_code"));
		resultMap.put("return_msg",paramMap.get("return_msg"));
		return resultMap;


	}
	private  InputStream getStringStream(String sInputString) throws UnsupportedEncodingException {
		ByteArrayInputStream tInputStringStream = null;
		if (sInputString != null && !sInputString.trim().equals("")) {
			tInputStringStream = new ByteArrayInputStream(sInputString.getBytes("UTF-8"));
		}
		return tInputStringStream;
	}



}
